package waf

import (
	"mallgo/internal/model/waf"
	"regexp"
	"strings"
	"sync"

	"mallgo/internal/common/response"
	"mallgo/internal/resources/waf/api/apis"

	"github.com/gin-gonic/gin"
	"golang.org/x/time/rate"
)

type WAF struct {
	ruleApi    apis.WafApi
	limiter    *rate.Limiter
	ipLimiters sync.Map
}

func NewWAF(ruleApi apis.WafApi) *WAF {
	return &WAF{
		ruleApi: ruleApi,
		limiter: rate.NewLimiter(rate.Limit(100), 200),
	}
}

// Middleware WAF中间件
func (w *WAF) Middleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		clientIP := c.ClientIP()

		// 1. IP限流检查
		if !w.checkRateLimit(clientIP) {
			c.JSON(200, response.Error(429, "请求过于频繁，请稍后再试"))
			c.Abort()
			return
		}

		// 2. IP黑白名单检查
		if !w.checkIP(clientIP) {
			c.JSON(200, response.Error(403, "IP访问被拒绝"))
			c.Abort()
			return
		}

		// 3. SQL注入检测
		if w.detectSQLInjection(c) {
			c.JSON(200, response.Error(403, "检测到SQL注入攻击"))
			c.Abort()
			return
		}

		// 4. XSS攻击检测
		if w.detectXSS(c) {
			c.JSON(200, response.Error(403, "检测到XSS攻击"))
			c.Abort()
			return
		}

		// 5. 敏感路径检查
		if w.detectSensitivePath(c.Request.URL.Path) {
			c.JSON(200, response.Error(403, "访问路径不允许"))
			c.Abort()
			return
		}

		// 6. 请求方法检查
		if !w.isAllowedMethod(c.Request.Method) {
			c.JSON(200, response.Error(405, "请求方法不允许"))
			c.Abort()
			return
		}

		c.Next()
	}
}

// checkRateLimit 检查IP限流
func (w *WAF) checkRateLimit(clientIP string) bool {
	// 全局限流检查
	if !w.limiter.Allow() {
		return false
	}

	// IP限流检查
	limiterI, _ := w.ipLimiters.LoadOrStore(clientIP,
		rate.NewLimiter(rate.Limit(10), 20)) // 每个IP每秒10个请求，突发20个
	limiter := limiterI.(*rate.Limiter)
	return limiter.Allow()
}

// checkIP 检查IP黑白名单
func (w *WAF) checkIP(clientIP string) bool {
	// 从API获取黑名单规则
	blacklistRes := w.ruleApi.GetRules("ip_blacklist")
	if blacklistRes.Code == 200 {
		if rules, ok := blacklistRes.Data.([]waf.Rule); ok {
			for _, rule := range rules {
				if rule.Pattern == clientIP {
					return false
				}
			}
		}
	}

	// 从API获取白名单规则
	whitelistRes := w.ruleApi.GetRules("ip_whitelist")
	if whitelistRes.Code == 200 {
		if rules, ok := whitelistRes.Data.([]waf.Rule); ok {
			if len(rules) > 0 {
				for _, rule := range rules {
					if rule.Pattern == clientIP {
						return true
					}
				}
				return false
			}
		}
	}

	return true
}

// detectSQLInjection SQL注入检测
func (w *WAF) detectSQLInjection(c *gin.Context) bool {
	params := w.getRequestParams(c)
	rulesRes := w.ruleApi.GetRules("sql_injection")

	if rulesRes.Code == 200 {
		if rules, ok := rulesRes.Data.([]waf.Rule); ok {
			for _, rule := range rules {
				r := regexp.MustCompile(rule.Pattern)
				for _, param := range params {
					if r.MatchString(strings.ToLower(param)) {
						return true
					}
				}
			}
		}
	}
	return false
}

// detectXSS XSS攻击检测
func (w *WAF) detectXSS(c *gin.Context) bool {
	params := w.getRequestParams(c)
	rulesRes := w.ruleApi.GetRules("xss")

	if rulesRes.Code == 200 {
		if rules, ok := rulesRes.Data.([]waf.Rule); ok {
			for _, rule := range rules {
				r := regexp.MustCompile(rule.Pattern)
				for _, param := range params {
					if r.MatchString(param) {
						return true
					}
				}
			}
		}
	}
	return false
}

// detectSensitivePath 检查敏感路径
func (w *WAF) detectSensitivePath(path string) bool {
	sensitivePatterns := []string{
		`(?i)/admin`,
		`(?i)/actuator`,
		`(?i)\.git`,
		`(?i)\.env`,
		`(?i)\.config`,
	}

	for _, pattern := range sensitivePatterns {
		r := regexp.MustCompile(pattern)
		if r.MatchString(path) {
			return true
		}
	}
	return false
}

// isAllowedMethod 检查请求方法是否允许
func (w *WAF) isAllowedMethod(method string) bool {
	allowedMethods := map[string]bool{
		"GET":     true,
		"POST":    true,
		"PUT":     true,
		"DELETE":  true,
		"OPTIONS": true,
	}
	return allowedMethods[method]
}

// getRequestParams 获取所有请求参数
func (w *WAF) getRequestParams(c *gin.Context) []string {
	var params []string

	// 获取URL参数
	query := c.Request.URL.Query()
	for _, values := range query {
		params = append(params, values...)
	}

	// 获取POST表单参数
	if c.Request.Method == "POST" {
		if err := c.Request.ParseForm(); err == nil {
			for _, values := range c.Request.PostForm {
				params = append(params, values...)
			}
		}
	}

	// 获取JSON参数
	var jsonParams map[string]interface{}
	if c.Request.Method == "POST" || c.Request.Method == "PUT" {
		if err := c.ShouldBindJSON(&jsonParams); err == nil {
			for _, value := range jsonParams {
				if str, ok := value.(string); ok {
					params = append(params, str)
				}
			}
		}
	}

	// 获取Header参数
	for _, values := range c.Request.Header {
		params = append(params, values...)
	}

	return params
}
